﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using ScrumFactory.Composition.ViewModel;
using ScrumFactory.Composition;
using ScrumFactory.Services;
using System.Windows.Input;
using System.Linq;
using System;
using ScrumFactory.Composition.View;
using ScrumFactory.Extensions;


namespace ScrumFactory.Backlog.ViewModel {

    /// <summary>
    /// Backlog item Detail View Model.
    /// </summary> 
    [Export]
    public class BacklogItemViewModel : BaseEditableObjectViewModel, IEditableObjectViewModel, INotifyPropertyChanged, IViewModel {

         private BacklogItem item;
         private BacklogItem oldItem;
         
         private IBacklogService backlogService;
         private IAuthorizationService authorizator;

         private IBackgroundExecutor executor;
         private IEventAggregator aggregator;

         private IDialogService dialogs;

         [Import]
         private Lazy<BacklogViewModel> backlog;

         private BacklogViewModel Backlog {
             get {
                 return backlog.Value;
             }
         }

        private bool isFirstTabSelected;
        public bool IsFirstTabSelected {
            get {
                return isFirstTabSelected;
            }
            set {
                isFirstTabSelected = value;
                OnPropertyChanged("IsFirstTabSelected");
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BacklogItemViewModel"/> class.
        /// </summary>
        /// <param name="backlogService">The backlog service.</param>
        /// <param name="backgroundExecutor">The background executor.</param>
        /// <param name="eventAggregator">The event aggregator.</param>
        /// <param name="item">The item.</param>
        [ImportingConstructor]
        public BacklogItemViewModel(
            [Import] IBacklogService backlogService,
            [Import] IBackgroundExecutor backgroundExecutor,
            [Import] IEventAggregator eventAggregator,
            [Import] IAuthorizationService authorizator,
            [Import] IDialogService dialogService) :
            this(backlogService, backgroundExecutor, eventAggregator, authorizator, null, null) {

                this.dialogs = dialogService;

                aggregator.Subscribe(ScrumFactoryEvent.ActiveSizesChanged, () => { OnPropertyChanged("Sizes"); });

                //aggregator.Subscribe<BacklogItem[]>(ScrumFactoryEvent.BacklogItemsChanged, UpdateChangedItems);


                FinishItemCommand = new DelegateCommand(CanEdit, FinishBacklogItem);

                SaveCommand = new DelegateCommand(CanEdit, SaveBacklogItem);            
                CloseWindowCommand = new DelegateCommand(CloseWindow);

                NavigateToNextItemCommand = new DelegateCommand(() => { NavigateToItem(1); });
                NavigateToPreviousItemCommand = new DelegateCommand(() => { NavigateToItem(-1); });
        }

        public BacklogItemViewModel() { }

        public BacklogItemViewModel(
            IBacklogService backlogService,
            IBackgroundExecutor backgroundExecutor,
            IEventAggregator eventAggregator,            
            IAuthorizationService authorizator,
            Project project,            
            BacklogItem item) {


                Init(backlogService, backgroundExecutor, eventAggregator, authorizator, project, item);

                ShowRepositoryLogCommand = new DelegateCommand(ShowRepositoryLog);        
                

        }

        public bool IgnoreChangeCommands { get; set; }

        public void Init(
            IBacklogService backlogService,
            IBackgroundExecutor backgroundExecutor,
            IEventAggregator eventAggregator,
            IAuthorizationService authorizator,
            Project project,
            BacklogItem item) {

            this.backlogService = backlogService;
            this.executor = backgroundExecutor;
            this.aggregator = eventAggregator;
            this.authorizator = authorizator;

            if (item != null) {
                this.Item = item;
                this.Item.Project = project;
                this.Item.SyncPlannedHoursAndRoles();
            }

            ChangeGroupCommand = new DelegateCommand(CanEdit, ChangeGroup);
            ChangeStatusCommand = new DelegateCommand(CanEdit, ChangeStatus);

            MoveItemToNextSprintCommand = new DelegateCommand(CanMoveItemToNextSprint, MoveItemToNextSprint);
            MoveItemToPreviousSprintCommand = new DelegateCommand(CanMoveItemToPreviousSprint, MoveItemToPreviousSprint);

            MoveItemToCurrentSprintCommand = new DelegateCommand(CanMoveItemToCurrentSprint, MoveItemToCurrentSprint);
            MoveItemToLastSprintCommand = new DelegateCommand(CanMoveItemToNextSprint, MoveItemToLastSprint);

            ShowTasksCommand = new DelegateCommand(ShowTasks);

        }

        private void ShowTasks() {
            aggregator.Publish<BacklogItem>(ScrumFactoryEvent.ShowTasksForItem, Item);
        }

        private void ShowRepositoryLog() {
            string filter = "#" + Item.Project.ProjectNumber + "." + Item.BacklogItemNumber + ".";
            aggregator.Publish<string>(ScrumFactoryEvent.ShowRepositoryLog, filter );
        }

        private decimal effectiveHours;
        public decimal EffectiveHours {
            get {
                return effectiveHours;
            }
            set {
                effectiveHours = value;
                OnPropertyChanged("EffectiveHours");
                OnPropertyChanged("HoursLeft");                
                OnPropertyChanged("PctHoursLeft");
                OnPropertyChanged("IsHoursLeftOverLimit");
            }
        }


        public bool IsDevelopmentItem {
            get {
                if (Item == null)
                    return true;
                return Item.OccurrenceConstraint == (int)ItemOccurrenceContraints.DEVELOPMENT;
            }
        }

        public void ShowDetail(BacklogItem item) {
            Item = item;
            oldItem = Item.Clone();
            Show();
        }

        public void Show() {
            SuggestedHours = null;
            IsFirstTabSelected = true;
            if(!View.IsVisible)
                aggregator.Publish<object>(ScrumFactoryEvent.ShowViewModel, this);
            if (IsPlanningLate)
                dialogs.ShowAlertMessage(Properties.Resources.Can_not_change_item_hours_Title, String.Format(Properties.Resources.Can_not_change_item_hours, Item.SprintNumber), null);

        }


        public bool IsPlanningLate {
            get {

                if (Item == null)
                    return false;

                // cant be late if is done
                if (Item.IsFinished)
                    return false;

                // cant be late if it has not started
                if (Item.Project!=null && Item.Project.Status != (short) ProjectStatus.PROJECT_STARTED)
                    return false;

                // no sprint assigned, so is late
                if (Sprint == null)
                    return true;

                // if sprint is over
                if (Sprint.EndDate.Date < System.DateTime.Today)
                    return true;

                // delivery date gone, is late
                if (Item.DeliveryDate.HasValue && Item.DeliveryDate.Value.Date < System.DateTime.Today)
                    return true;

                return false;
            }
        }


        public bool UserCannotEdit {
            get {
                if (Item == null)
                    return false;
                return ! Item.Project.HasPermission(authorizator.SignedMemberProfile.MemberUId, PermissionSets.SCRUM_MASTER);
            }
        }

        public bool UserCannotEditHours {
            get {
                if (UserCannotEdit)
                    return true;
                return !Item.CanEditHours;
            }
        }

        private void NavigateToItem(int offset) {
            if (ItemHasChanged)
                SaveBacklogItem(() => { Backlog.NavigateToItem(offset); });
            else
                Backlog.NavigateToItem(offset);
        }
        
        /// <summary>
        /// Closes the window, invoke the OnCloseAction and publishes the CloseWindow event.
        /// </summary>
        private void CloseWindow() {

            dialogs.CloseAlertMessage();

            if (!UserCannotEdit && ItemHasChanged)
                SaveBacklogItem();

            aggregator.Publish<IViewModel>(ScrumFactoryEvent.CloseViewModel, this);
            if (OnCloseAction != null)
                OnCloseAction.Invoke(this);                  

        }

        public string PlannedHoursToolTip {
            get {
                string tooltip = "";
                foreach (PlannedHour h in Item.PlannedHours)
                    tooltip = tooltip + h.Hours + " " + h.Role.RoleShortName + "; ";
                return tooltip;
            }
        }

        /// <summary>
        /// Saves the item, detecting if the planned hours were changed or not.
        /// </summary>
        private void SaveBacklogItem() {
            SaveBacklogItem(null);
        }

        private void SaveBacklogItem(Action afterSave) {

            executor.StartBackgroundTask(
                () => {
                    // if the planned hours was not changed, dont update it
                    if (!Item.HasTheSameHours(oldItem))
                        backlogService.UpdateBacklogItem(Item.BacklogItemUId, Item);
                    else
                        backlogService.UpdateBacklogItemIgnoringHours(Item.BacklogItemUId, Item);
                },
                () => {
                    RefreshUI(); // need this to refresh item in the list

                    aggregator.Publish<BacklogItem[]>(ScrumFactoryEvent.BacklogItemsChanged, new BacklogItem[] { this.Item });

                    // clean the original values
                    oldItem = item.Clone();
                    oldItem.Project = item.Project;
                    oldItem.SyncPlannedHoursAndRoles();

                    //oldItem = null;

                    if(afterSave!=null)
                        afterSave.Invoke();
                });

        }

        private void ChangeGroup() {
            if (isDisposed || IgnoreChangeCommands)
                return;
            //if (Backlog.GroupList.IsLoadingData)
            //    return;
            executor.StartBackgroundTask(
                () => {
                    backlogService.ChangeBacklogItemGroup(Item.BacklogItemUId, Item.GroupUId);
                },
                () => { });         
        }

        private void ChangeStatus() {
            if (isDisposed || IgnoreChangeCommands)
                return;
            executor.StartBackgroundTask(
                () => {
                    backlogService.ChangeBacklogItemStatus(Item.BacklogItemUId, Item.Status);
                },
                () => {

                });
        }

        private void FinishBacklogItem() {
            if (isDisposed)
                return;
            Item.Status = (short)BacklogItemStatus.ITEM_DONE;
            ChangeStatus();
        }

        private bool ItemHasChanged {
            get {
                return !item.IsTheSame(oldItem);
            }
        }

        
        public bool HasDeliveryDate {
            get {
                if (Item == null)
                    return false;
                return Item.DeliveryDate != null;
            }
            set {
                if (!value)
                    DeliveryDate = null;
                else
                    DeliveryDate = SprintEndDate;                
                OnPropertyChanged("HasDeliveryDate");
            }
        }

      

        
        [Import(typeof(BacklogItemDetail))]
        public IView View { get; set; }


        #region IPanelViewModel Members

        /// <summary>
        /// Gets the panel display order when it is displayed at the view.
        /// </summary>
        /// <value>The panel display order.</value>
        public int PanelDisplayOrder {
            get {
                return 100;
            }
        }

        /// <summary>
        /// Gets the name of the panel.
        /// </summary>
        /// <value>The name of the panel.</value>
        public string PanelName {
            get {
                if (Item == null)
                    return Properties.Resources.Backlog_item + "?";
                return Properties.Resources.Backlog_item + " " + Item.BacklogItemNumber;
            }
        }

       


        
        #endregion

        #region IBacklogItemViewModel Members


        /// <summary>
        /// Gets the sizes.
        /// </summary>
        /// <value>The sizes.</value>
        public ICollection<SizeViewModel> Sizes {
            get {
                return Backlog.ActiveSizes;
            }            
        }

        /// <summary>
        /// Refreshes the corresponding View Model view.
        /// </summary>
        public void RefreshUI() {
            OnPropertyChanged("Item");
            OnPropertyChanged("PanelName");
            OnPropertyChanged("ItemTotalHoursInPixels");            
            OnPropertyChanged("PlannedHours");
            OnPropertyChanged("ShowPlanningNumberLabel");
            OnPropertyChanged("ItemSprintLabel");
            OnPropertyChanged("ItemSizeUId");
            OnPropertyChanged("ItemSize");
            OnPropertyChanged("ItemStatus");
            OnPropertyChanged("ItemSizeString");

            OnPropertyChanged("IsPlanningLate");

            OnPropertyChanged("PlannedHoursToolTip");

            OnPropertyChanged("SizeFactor");
            OnPropertyChanged("UserCannotEdit");
            //OnPropertyChanged("CanMoveItemToPreviousSprint");
            //OnPropertyChanged("CanMoveItemToNextSprint");
            OnPropertyChanged("IsAtCurrentSprint");
            OnPropertyChanged("IsDevelopmentItem");

            if(MoveItemToCurrentSprintCommand!=null)
                ((DelegateCommand)MoveItemToCurrentSprintCommand).NotifyCanExecuteChanged();
        }

        /// <summary>
        /// Gets the planned hours for this item.
        /// </summary>
        /// <value>The planned hours.</value>
        public ICollection<PlannedHour> PlannedHours {
            get {
                // no item, no candy
                if (item == null)
                    return null;
                // item has no hours planned, create it with zero
                //if (item.PlannedHours == null || item.PlannedHours.Count == 0)
                //    item.SyncPlannedHoursAndRoles(item.Project.CurrentValidSprint.SprintNumber);
                return item.PlannedHours.OrderBy(p => p.Role.PermissionSet).ToList();
            }
        }

        private ICollection<PlannedHour> suggestedHours;
        public ICollection<PlannedHour> SuggestedHours {
            get {
                if (suggestedHours == null)
                    return null;
                return suggestedHours.OrderBy(p => p.Role.PermissionSet).ToList();
            }
            set {
                suggestedHours = value;
                OnPropertyChanged("SuggestedHours");
            }
        }

        /// <summary>
        /// Gets the item.
        /// </summary>
        /// <value>The item.</value>
        public BacklogItem Item {
            get { return item; }
            set {
                //ItemSize = null;
                item = value;                                
                RefreshUI();
            }
        }

        public decimal HoursLeft {
            get {                
                return Item.CurrentTotalHours - EffectiveHours;
            }
        }


        public decimal PctHoursLeft {
            get {
                if (Item.CurrentTotalHours == 0 && HoursLeft==0)
                    return 1;
                if (Item.CurrentTotalHours == 0 && HoursLeft < 0)
                    return 0;
                decimal pct = HoursLeft / Item.CurrentTotalHours;
                if (pct < 0)
                    pct = 0;
                return pct;
            }
        }

        public short IsHoursLeftOverLimit {
            get {
                if (PctHoursLeft < (decimal)0.2)
                    return 2;
                if (PctHoursLeft < (decimal)0.5)
                    return 1;
                return 0;
            }
        }


        /// <summary>
        /// Gets or sets the item status.
        /// </summary>
        /// <value>The item status.</value>
        public short ItemStatus {
            get {
                if (item == null)
                    return 0;
                return item.Status;
            }
            set {
                item.Status = value;
                OnPropertyChanged("Item");                
            }
        }
        
        public SizeViewModel ItemSize {
            get {
                if (Sizes == null)
                    return null;
                return Sizes.SingleOrDefault(z => z.ItemSize.ItemSizeUId == Item.ItemSizeUId);
            }
            set {
                CalcSize(value);
                CalcSuggestedHours();
            }
        }

        private void CalcSize() {
            CalcSize(ItemSize);
        }

        private void CalcSize(SizeViewModel sizeVM) {
            if (Item == null)
                return;

            if (sizeVM != null) {
                Item.ItemSizeUId = sizeVM.ItemSize.ItemSizeUId;
                Item.Size = sizeVM.ItemSize.Size * Item.SizeFactor;
            }
            else {
                Item.Size = null;
                Item.ItemSizeUId = null;
            }

            OnPropertyChanged("ItemSize");
            OnPropertyChanged("ItemSizeString");
        }

        public int SizeFactor {
            get {
                if (Item == null)
                    return 0;
                return Item.SizeFactor;
            }
            set {
                Item.SizeFactor = value;
                CalcSize();
                OnPropertyChanged("SizeFactor");
            }
        }

        private void CalcSuggestedHours() {

            if (Item == null)
                return;
            
            if (Item.ItemSizeUId == null)
                return;

            executor.StartBackgroundTask<Dictionary<string, decimal?>>(
                () => { return backlogService.GetVelocityBySize(Item.ItemSizeUId); },
                vel => {                    
                    List<PlannedHour> suggestedHours = new List<PlannedHour>();
                    foreach (Role r in Item.Project.Roles) {
                        decimal hours = 0;
                        if (vel.ContainsKey(r.RoleShortName)) {
                           decimal? ptsHrs = vel[r.RoleShortName];
                           if (!ptsHrs.HasValue || ptsHrs == 0)
                               hours = 0;
                           else
                               hours = (decimal)Item.Size / ptsHrs.Value;

                        }
                        suggestedHours.Add(new PlannedHour() { Hours = hours, Role = r });                        
                    }
                    SuggestedHours = suggestedHours;                    
                });            
        }

        public string ItemSizeString {
            get {
                if (Item.Size == null)
                    return "?";
                return Item.Size.ToString();
            }            
        }

        /// <summary>
        /// Gets the item sprint label.
        /// It could be the localized string for "Next Sprint", "Current Sprint", etc...
        /// </summary>
        /// <value>The item sprint label.</value>
        public string ItemSprintLabel {
            get {
                if (Item == null || Item.Project == null)
                    return "";

                if (Item.SprintNumber == null)
                    return Properties.Resources.plan;

                return string.Format(Properties.Resources.sprint_N, Item.SprintNumber);

                //Sprint currentSprint = Item.Project.CurrentSprint;

                //if (currentSprint == null || !Item.Project.IsRunning)
                //    return string.Format(Properties.Resources.sprint_N, Item.SprintNumber);

                //if (currentSprint.SprintNumber == Item.SprintNumber)
                //    return Properties.Resources.current_sprint;

                //if (currentSprint.SprintNumber + 1 == Item.SprintNumber)
                //    return Properties.Resources.next_sprint;

                //if (currentSprint.SprintNumber - 1 == Item.SprintNumber)
                //    return Properties.Resources.previous_sprint;

                //return string.Format(Properties.Resources.sprint_N, Item.SprintNumber);
            }
        }

        public bool IsAtCurrentSprint {
            get {
                if (Item == null || Item.SprintNumber == null || Item.Project == null)
                    return false;

                Sprint currentSprint = Item.Project.CurrentSprint;

                if (currentSprint == null || !Item.Project.IsRunning)
                    return false;

                if (currentSprint.SprintNumber == Item.SprintNumber)
                    return true;

                return false;

            }
        }

        /// <summary>
        /// Changes the item sprint.
        /// </summary>
        /// <param name="sprintNumber">The new sprint number.</param>
        /// <param name="lowPriority">if set to <c>true</c> the item is placed at the end of the sprint.</param>
        public void ChangeSprint(int sprintNumber, bool lowPriority) {
           
            executor.StartBackgroundTask<BacklogItem[]>(
                () => { return backlogService.ChangeItemSprint(item.BacklogItemUId, sprintNumber, lowPriority); },
                changedItems => {
                    Item.SprintNumber = sprintNumber;
                    aggregator.Publish<BacklogItem[]>(ScrumFactoryEvent.BacklogItemsChanged, changedItems);                                   
                });
        }

        /// <summary>
        /// Moves the item to another item position.
        /// </summary>        
        /// <param name="targetItem">The target item.</param>
        public void MoveItemTo(BacklogItem targetItem) {

            executor.StartBackgroundTask<BacklogItem[]>(
                () => { return backlogService.MoveItem(item.BacklogItemUId, targetItem.BacklogItemUId); },
                changedItems => {
                    if (changedItems == null)
                        return;
                    BacklogItem updatedItem = changedItems.SingleOrDefault(i => i.BacklogItemUId == Item.BacklogItemUId);
                    if (updatedItem != null)
                        Item.SprintNumber = updatedItem.SprintNumber;
                    aggregator.Publish<BacklogItem[]>(ScrumFactoryEvent.BacklogItemsChanged, changedItems);                                                            
                });
        }

        private bool CanEdit() {
            return !UserCannotEdit;
        }

        private void MoveItemToNextSprint() {            
            int sprintNumber;
            if (Item.SprintNumber == null)
                sprintNumber = Item.Project.CurrentValidSprint.SprintNumber;
            else
                sprintNumber = (int)Item.SprintNumber + 1;

            ChangeSprint(sprintNumber, false);
        }

        private void MoveItemToPreviousSprint() {
            if (Item.SprintNumber == null || Item.SprintNumber==1)
                return;
            ChangeSprint((int)Item.SprintNumber -1, false);
        }

        private void MoveItemToLastSprint() {
            
            ChangeSprint(Item.Project.LastSprint.SprintNumber, false);            
        }

        private void MoveItemToCurrentSprint() {

            ChangeSprint(Item.Project.CurrentValidSprint.SprintNumber, false);
        }

        public void UpdateChangedItems(BacklogItem[] changedItems) {
            if (isDisposed)
                return;
            if (changedItems == null || Item == null)
                return;
            BacklogItem changedItem = changedItems.SingleOrDefault(i => i.BacklogItemUId == Item.BacklogItemUId);
            if(changedItem==null)
                return;

            changedItem.Project = Item.Project;
            changedItem.SyncPlannedHoursAndRoles();
            Item = changedItem;
            
        }


        private bool CanMoveItemToCurrentSprint() {
            if (Item.Project == null || Item.Project.Sprints == null)
                return false;
            if (UserCannotEdit)
                return false;
            if (Item.Status == (short)BacklogItemStatus.ITEM_DONE || Item.Status == (short)BacklogItemStatus.ITEM_CANCELED)
                return false;
            if (Item.OccurrenceConstraint != (int)ItemOccurrenceContraints.DEVELOPMENT)
                return false;
            if (Item.Project.CurrentSprint == null)
                return false;
            return !Item.SprintNumber.Equals(Item.Project.CurrentSprint.SprintNumber);
        }

        
        private bool CanMoveItemToNextSprint() {            
                if (Item.Project == null || Item.Project.Sprints == null)
                    return false;
                if (UserCannotEdit)
                    return false;
                if (Item.Status == (short)BacklogItemStatus.ITEM_DONE || Item.Status == (short)BacklogItemStatus.ITEM_CANCELED)
                    return false;
                if (Item.OccurrenceConstraint != (int)ItemOccurrenceContraints.DEVELOPMENT)
                    return false;
                return !Item.SprintNumber.Equals(Item.Project.LastSprint.SprintNumber);
        }

        
        private bool CanMoveItemToPreviousSprint() {
            
                if (Item.Project == null || Item.Project.Sprints == null)
                    return false;
                if (UserCannotEdit)
                    return false;
                if (Item.Status == (short)BacklogItemStatus.ITEM_DONE || Item.Status == (short)BacklogItemStatus.ITEM_CANCELED)
                    return false;
                if (Item.OccurrenceConstraint != (int)ItemOccurrenceContraints.DEVELOPMENT)
                    return false;
                return Item.SprintNumber > Item.Project.CurrentValidSprint.SprintNumber;
            
        }


        /// <summary>
        /// Gets the item total hours in pixels, so it can be displayied at the Sprint Panel.
        /// </summary>
        /// <value>The item total hours in pixels.</value>
        public double ItemTotalHoursInPixels {
            get {
                if (Item.CurrentTotalHours < 8)
                    return 24;
                if (Item.CurrentTotalHours > 90)
                    return 90 * 3;
                return (double)Item.CurrentTotalHours * 3;
            }
        }

        public System.DateTime? DeliveryDate {
            get {
                if (Item == null)
                    return null;
                if (Item.DeliveryDate != null)
                    return Item.DeliveryDate;

                if (Item.Project == null)
                    return null;
                
                if (Item.Project.Sprints == null)
                    return null;

                return SprintEndDate;
            }
            set {
                Item.DeliveryDate = value;
                OnPropertyChanged("DeliveryDate");
            }
        }

        private DateTime? SprintEndDate {
            get {         
                if (Sprint == null)
                    return null;
                return Sprint.EndDate;
            }
        }

        public Sprint Sprint {
            get {
                if (Item==null || Item.Project == null || Item.Project.Sprints==null)
                    return null;
                return Item.Project.Sprints.SingleOrDefault(s => s.SprintNumber == Item.SprintNumber);                
            }
        }

        /// <summary>
        /// Gets or sets the on close action that is executed after a backlog item has been edited
        /// at the detail window.
        /// </summary>
        /// <value>The on close action.</value>
        public System.Action<BacklogItemViewModel> OnCloseAction { get; set; }

        /// <summary>
        /// Gets the close window command.
        /// </summary>
        /// <value>The close window command.</value>
        public ICommand CloseWindowCommand { get; private set; }


        public ICommand SaveCommand { get; set; }

        public ICommand ChangeGroupCommand { get; set; }
        public ICommand ChangeStatusCommand { get; set; }

        public ICommand FinishItemCommand { get; set; }


        /// <summary>
        /// Gets the move item to next sprint command.
        /// </summary>
        /// <value>The move item to next sprint command.</value>
        public ICommand MoveItemToNextSprintCommand { private set; get; }

        /// <summary>
        /// Gets the move item to previous sprint command.
        /// </summary>
        /// <value>The move item to previous sprint command.</value>
        public ICommand MoveItemToPreviousSprintCommand { private set; get; }

        /// <summary>
        /// Gets the move item to last sprint command.
        /// </summary>
        /// <value>The move item to last sprint command.</value>
        public ICommand MoveItemToLastSprintCommand { private set; get; }

        /// <summary>
        /// Gets the move item to last sprint command.
        /// </summary>
        /// <value>The move item to last sprint command.</value>
        public ICommand MoveItemToCurrentSprintCommand { private set; get; }

        
        /// <summary>
        /// Gets or sets the navigate to next item command.
        /// </summary>
        /// <value>The navigate to next item command.</value>
        public ICommand NavigateToNextItemCommand { get; set; }


        /// <summary>
        /// Gets or sets the navigate to previous item command.
        /// </summary>
        /// <value>The navigate to previous item command.</value>
        public ICommand NavigateToPreviousItemCommand { get; set; }

        public ICommand ShowTasksCommand { get; set; }

        public ICommand ShowRepositoryLogCommand { get; set; }

        /// <summary>
        /// Make sure to unbind all commands.
        /// </summary>
        protected override void OnDispose() {

            aggregator.UnSubscribeAll(this);

            FinishItemCommand = null; OnPropertyChanged("FinishItemCommand");
            SaveCommand = null; OnPropertyChanged("SaveCommand");
            ChangeGroupCommand = null; OnPropertyChanged("ChangeGroupCommand");
            CloseWindowCommand = null; OnPropertyChanged("CloseWindowCommand");
            MoveItemToNextSprintCommand = null; OnPropertyChanged("MoveItemToNextSprintCommand");
            MoveItemToPreviousSprintCommand = null; OnPropertyChanged("MoveItemToPreviousSprintCommand");
            MoveItemToLastSprintCommand = null; OnPropertyChanged("MoveItemToLastSprintCommand");
            NavigateToNextItemCommand = null; OnPropertyChanged("NavigateToNextItemCommand");
            NavigateToPreviousItemCommand = null; OnPropertyChanged("NavigateToPreviousItemCommand");            
            ChangeStatusCommand = null; OnPropertyChanged("ChangeStatusCommand");
            MoveItemToCurrentSprintCommand = null; OnPropertyChanged("MoveItemToCurrentSprintCommand");
            ShowTasksCommand = null; OnPropertyChanged("ShowTasksCommand");
            ShowRepositoryLogCommand = null; OnPropertyChanged("ShowRepositoryLogCommand");
            
        }

        ~BacklogItemViewModel() {
            System.Console.WriteLine("***< item died here");
        }
        
        #endregion
    }
}
